Skip to content

dash_charts.utils_app_with_navigation⚓︎

Classes for more complex applications that have tabbed or paged navigation.

View Source

"""Classes for more complex applications that have tabbed or paged navigation."""

from collections import OrderedDict
from copy import deepcopy

import dash_bootstrap_components as dbc
from dash import dcc, html
from implements import implements

from .utils_app import AppBase, AppInterface

TODO_CLIENT_CALLBACK = '''
TODO: Create clientside callbacks dynamically to update the title on navigation
See: http://dash.plotly.com/external-resources
```py
app.clientside_callback(
    """
    function(tab_value) {
        if (tab_value === 'tab-1') {
            document.title = 'Tab 1'
        } else if (tab_value === 'tab-2') {
            document.title = 'Tab 2'
        }
    }
    """,
    Output('blank-output', 'children'),
    [Input('tabs-example', 'value')]
)
‘’‘

TODO: Try to see if I can resolve the interface differences or if I need make a subclass interface⚓︎

@implements(AppInterface) # noqa: H601⚓︎

class AppWithNavigation(AppBase): “”“Base class for building Dash Application with tabs or URL routing.”“”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
app = None
"""Main Dash application to pass to all child tabs."""

nav_lookup = None
"""OrderedDict based on the list of tuples from `self.define_nav_elements()`."""

nav_layouts = None
"""Dictionary with nav_names as keys and corresponding layout as value."""

def define_nav_elements(self):
    """Return list of initialized pages or tabs accordingly.

    Should return, list: each item is an initialized app (ex `[AppBase(self.app)]` in the order each tab is rendered

    Raises:
        NotImplementedError: Child class must implement this method

    """
    raise NotImplementedError('define_nav_elements must be implemented by child class')  # pragma: no cover

def create(self, **kwargs):
    """Create each navigation componet, storing the layout. Then parent class to create application.

    Args:
        kwargs: keyword arguments passed to `self.create`

    """
    # Initialize the lookup for each tab then configure each tab
    self.nav_lookup = OrderedDict([(tab.name, tab) for tab in self.define_nav_elements()])
    self.nav_layouts = {}
    for nav_name, nav in self.nav_lookup.items():
        nav.create(assign_layout=False)
        self.nav_layouts[nav_name] = nav.return_layout()

    # Store validation_layout that is later used for callback verification in base class
    self.validation_layout = [*map(deepcopy, self.nav_layouts.values())]

    # Initialize parent application that handles navigation
    super().create(**kwargs)

def initialization(self) -> None:
    """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
    super().initialization()
    self.register_uniq_ids(self.app_ids)

def create_elements(self) -> None:
    """Override method as not needed at navigation-level."""
    ...  # pragma: no cover

def create_callbacks(self) -> None:
    """Override method as not needed at navigation-level."""
    ...  # pragma: no cover

@implements(AppInterface) # noqa: H601 class StaticTab(AppBase): “”“Simple App without charts or callbacks.”“”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
basic_style = {
    'marginLeft': 'auto',
    'marginRight': 'auto',
    'maxWidth': '1000px',
    'paddingTop': '10px',
}

def initialization(self) -> None:
    """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
    super().initialization()
    self.register_uniq_ids(['N/A'])

def create_elements(self) -> None:
    """Initialize the charts, tables, and other Dash elements.."""
    ...

def create_callbacks(self) -> None:
    """Register callbacks necessary for this tab."""
    ...

class AppWithTabs(AppWithNavigation): “”“Base class for building Dash Application with tabs.”“”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# App ids
id_tabs_content = 'tabs-wrapper'
id_tabs_select = 'tabs-content'

app_ids = [id_tabs_content, id_tabs_select]
"""List of all ids for the top-level tab view. Will be mapped to `self._il` for globally unique ids."""

def return_layout(self) -> dict:
    """Return Dash application layout.

    Returns:
        dict: Dash HTML object

    """
    tabs = [dcc.Tab(label=name, value=name) for name, tab in self.nav_lookup.items()]
    return html.Div(
        children=[
            dcc.Tabs(
                id=self._il[self.id_tabs_select], value=list(self.nav_lookup.keys())[0],
                children=tabs,
            ),
            html.Div(id=self._il[self.id_tabs_content]),
        ],
    )

def create_callbacks(self) -> None:
    """Register the navigation callback."""
    outputs = [(self.id_tabs_content, 'children')]
    inputs = [(self.id_tabs_select, 'value')]

    @self.callback(outputs, inputs, [])
    def render_tab(tab_name):
        return [self.nav_layouts[tab_name]]

> PLANNED: Make the tabs and chart compact as well when the compact argument is set to True⚓︎

class FullScreenAppWithTabs(AppWithTabs): # noqa: H601 “”“Base class for building Dash Application with tabs that uses the full window.”“”

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
tabs_location = 'left'
"""Tab orientation setting. One of `(left, top, bottom, right)`."""

tabs_margin = '10%'
"""Adjust this setting based on the width or height of the tabs to prevent the content from overlapping the tabs."""

tabs_compact = False
"""Boolean setting to toggle between a padded tab layout if False and a minimal compact version if True."""

def verify_app_initialization(self):
    """Check that the app was properly initialized.

    Raises:
        RuntimeError: if child class has not called `self.register_uniq_ids`

    """
    super().verify_app_initialization()
    allowed_locations = ('left', 'top', 'bottom', 'right')
    if self.tabs_location not in allowed_locations:  # pragma: no cover
        raise RuntimeError(f'`self.tabs_location = {self.tabs_location}` is not in {allowed_locations}')

def return_layout(self) -> dict:
    """Return Dash application layout.

    Returns:
        dict: Dash HTML object

    """
    return html.Div(
        children=[
            self.tab_menu(),
            html.Div(
                style={f'margin-{self.tabs_location}': self.tabs_margin},
                children=[html.Div(id=self._il[self.id_tabs_content])],
            ),
        ],
    )

def generate_tab_kwargs(self):
    """Create the tab keyword arguments. Intended to be modified through inheritance.

    Returns:
        tuple: keyword arguments and styling for the dcc.Tab elements

            - tab_kwargs: with at minimum keys `(style, selected_style)` for dcc.Tab
            - tabs_kwargs: to be passed to dcc.Tabs
            - tabs_style: style for the dcc.Tabs HTML element

    """
    # Unselected tab style
    if self.tabs_compact:
        tab_style = {'padding': '2px 4px 2px 4px'}
        tabs_padding = '6px 0 0 2px'
    else:
        tab_style = {'padding': '10px 20px 10px 20px'}
        tabs_padding = '15px 0 0 5px'
    # Extend tab style for selected case
    selected_style = deepcopy(tab_style)
    opposite_lookup = {'top': 'bottom', 'bottom': 'top', 'left': 'right', 'right': 'left'}
    tabs_style = {   # noqa: ECE001
        'backgroundColor': '#F9F9F9',
        'padding': tabs_padding,
        'position': 'fixed',
        'zIndex': '999',
        f'border{opposite_lookup[self.tabs_location].title()}': '1px solid #d6d6d6',
        self.tabs_location: '0',
    }
    if self.tabs_location in ['left', 'right']:
        # Configure for vertical case
        selected_style['border-left'] = '3px solid #119DFF'
        tabs_kwargs = {
            'vertical': True,
            'style': {'width': '100%'},
            'parent_style': {'width': '100%'},
        }
        tabs_style['top'] = '0'
        tabs_style['bottom'] = '0'
        tabs_style['width'] = 'auto'
    else:
        # Configure for horizontal case
        selected_style['border-top'] = '3px solid #119DFF'
        tabs_kwargs = {}
        tabs_style['height'] = 'auto'
        tabs_style['right'] = '0'
        tabs_style['left'] = '0'

    tab_kwargs = {'style': tab_style, 'selected_style': selected_style}
    return (tab_kwargs, tabs_kwargs, tabs_style)

def tab_menu(self):
    """Return the HTML elements for the tab menu.

    Returns:
        dict: Dash HTML object

    """
    tab_kwargs, tabs_kwargs, tabs_style = self.generate_tab_kwargs()
    tabs = [dcc.Tab(label=name, value=name, **tab_kwargs) for name, tab in self.nav_lookup.items()]
    return html.Div(
        children=[
            dcc.Tabs(
                id=self._il[self.id_tabs_select], value=list(self.nav_lookup.keys())[0],
                children=tabs, **tabs_kwargs,
            ),
        ], style=tabs_style,
    )

class AppMultiPage(AppWithNavigation): # noqa: H601 “”“Base class for building Dash Application with multiple pages.”“”

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
navbar_links = None
"""Base class must create list of tuples `[('Link Name', '/link'), ]` to use default `self.nav_bar()`."""

dropdown_links = None
"""Base class must create list of tuples `[('Link Name', '/link'), ]` to use default `self.nav_bar()`."""

logo = None
"""Optional path to logo. If None, no logo will be shown in navbar."""

# App ids
id_url = 'pages-url'
id_pages_content = 'pages-wrapper'
id_toggler = 'nav-toggle'
id_collapse = 'nav-collapse'

app_ids = [id_url, id_pages_content, id_toggler, id_collapse]
"""List of all ids for the top-level pages view. Will be mapped to `self._il` for globally unique ids."""

def return_layout(self) -> dict:
    """Return Dash application layout.

    Returns:
        dict: Dash HTML object

    """
    return html.Div(
        children=[
            dcc.Location(id=self._il[self.id_url], refresh=False),
            self.nav_bar(),
            html.Div(id=self._il[self.id_pages_content]),
        ],
    )

def nav_bar(self):
    """Return the HTML elements for the navigation menu.

    Returns:
        dict: Dash HTML object

    """
    # Create brand icon and name where icon in optional
    brand = []
    if self.logo:
        brand.append(dbc.Col(html.Img(src=self.logo, height='25px')))
    brand.append(dbc.Col(dbc.NavbarBrand(self.name, className='ml-2')))
    # Create links in navbar and dropdown. Both are optional
    links = []
    if self.navbar_links:
        links.append(
            dbc.Nav(
                children=[dbc.NavItem(dbc.NavLink(name, href=link)) for name, link in self.navbar_links],
                fill=True,
                navbar=True,
            ),
        )
    if self.dropdown_links:
        links.append(
            dbc.Nav(
                dbc.DropdownMenu(
                    children=[dbc.DropdownMenuItem(name, href=link) for name, link in self.dropdown_links],
                    in_navbar=True,
                    label='Links',
                    nav=True,
                ),
                navbar=True,
            ),
        )
    # Layout default navbar
    return dbc.Navbar(
        children=[
            dbc.NavLink(
                [
                    dbc.Row(
                        children=brand,
                        align='center g-0',
                    ),
                ], href='/',
            ),
            dbc.NavbarToggler(id=self._il[self.id_toggler]),
            dbc.Collapse(
                dbc.Row(
                    children=links,
                    className='flex-nowrap mt-3 mt-md-0 g-0',
                    align='center',
                ),
                id=self._il[self.id_collapse],
                navbar=True,
            ),
        ],
        sticky='top',
        color='dark',
        dark=True,
    )

def create_callbacks(self) -> None:
    """Register the navigation callback."""
    outputs = [(self.id_pages_content, 'children')]
    inputs = [(self.id_url, 'pathname')]

    @self.callback(outputs, inputs, [])
    def render_page(pathname):
        try:
            # TODO: Demo how pages could use parameters from pathname
            return [self.nav_layouts[self.select_page_name(pathname)]]
        except Exception as err:
            return [html.Div(children=[f'Error rendering "{pathname}":\n{err}'])]

    @self.callback(
        [(self.id_collapse, 'is_open')],
        [(self.id_toggler, 'n_clicks')],
        [(self.id_collapse, 'is_open')],
    )
    def toggle_navbar_collapse(n_clicks, is_open):
        return [not is_open if n_clicks else is_open]

def select_page_name(self, pathname):
    """Return the page name determined based on the pathname.

    Should return str: page name

    Args:
        pathname: relative pathname from URL

    Raises:
        NotImplementedError: Child class must implement this method

    """
    raise NotImplementedError('nav_bar must be implemented by child class')  # pragma: no cover

```

Variables⚓︎

TODO_CLIENT_CALLBACK

Classes⚓︎

AppMultiPage⚓︎

class AppMultiPage(
    app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class AppMultiPage(AppWithNavigation):  # noqa: H601
    """Base class for building Dash Application with multiple pages."""

    navbar_links = None
    """Base class must create list of tuples `[('Link Name', '/link'), ]` to use default `self.nav_bar()`."""

    dropdown_links = None
    """Base class must create list of tuples `[('Link Name', '/link'), ]` to use default `self.nav_bar()`."""

    logo = None
    """Optional path to logo. If None, no logo will be shown in navbar."""

    # App ids
    id_url = 'pages-url'
    id_pages_content = 'pages-wrapper'
    id_toggler = 'nav-toggle'
    id_collapse = 'nav-collapse'

    app_ids = [id_url, id_pages_content, id_toggler, id_collapse]
    """List of all ids for the top-level pages view. Will be mapped to `self._il` for globally unique ids."""

    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object

        """
        return html.Div(
            children=[
                dcc.Location(id=self._il[self.id_url], refresh=False),
                self.nav_bar(),
                html.Div(id=self._il[self.id_pages_content]),
            ],
        )

    def nav_bar(self):
        """Return the HTML elements for the navigation menu.

        Returns:
            dict: Dash HTML object

        """
        # Create brand icon and name where icon in optional
        brand = []
        if self.logo:
            brand.append(dbc.Col(html.Img(src=self.logo, height='25px')))
        brand.append(dbc.Col(dbc.NavbarBrand(self.name, className='ml-2')))
        # Create links in navbar and dropdown. Both are optional
        links = []
        if self.navbar_links:
            links.append(
                dbc.Nav(
                    children=[dbc.NavItem(dbc.NavLink(name, href=link)) for name, link in self.navbar_links],
                    fill=True,
                    navbar=True,
                ),
            )
        if self.dropdown_links:
            links.append(
                dbc.Nav(
                    dbc.DropdownMenu(
                        children=[dbc.DropdownMenuItem(name, href=link) for name, link in self.dropdown_links],
                        in_navbar=True,
                        label='Links',
                        nav=True,
                    ),
                    navbar=True,
                ),
            )
        # Layout default navbar
        return dbc.Navbar(
            children=[
                dbc.NavLink(
                    [
                        dbc.Row(
                            children=brand,
                            align='center g-0',
                        ),
                    ], href='/',
                ),
                dbc.NavbarToggler(id=self._il[self.id_toggler]),
                dbc.Collapse(
                    dbc.Row(
                        children=links,
                        className='flex-nowrap mt-3 mt-md-0 g-0',
                        align='center',
                    ),
                    id=self._il[self.id_collapse],
                    navbar=True,
                ),
            ],
            sticky='top',
            color='dark',
            dark=True,
        )

    def create_callbacks(self) -> None:
        """Register the navigation callback."""
        outputs = [(self.id_pages_content, 'children')]
        inputs = [(self.id_url, 'pathname')]

        @self.callback(outputs, inputs, [])
        def render_page(pathname):
            try:
                # TODO: Demo how pages could use parameters from pathname
                return [self.nav_layouts[self.select_page_name(pathname)]]
            except Exception as err:
                return [html.Div(children=[f'Error rendering "{pathname}":\n{err}'])]

        @self.callback(
            [(self.id_collapse, 'is_open')],
            [(self.id_toggler, 'n_clicks')],
            [(self.id_collapse, 'is_open')],
        )
        def toggle_navbar_collapse(n_clicks, is_open):
            return [not is_open if n_clicks else is_open]

    def select_page_name(self, pathname):
        """Return the page name determined based on the pathname.

        Should return str: page name

        Args:
            pathname: relative pathname from URL

        Raises:
            NotImplementedError: Child class must implement this method

        """
        raise NotImplementedError('nav_bar must be implemented by child class')  # pragma: no cover

Ancestors (in MRO)⚓︎

  • dash_charts.utils_app_with_navigation.AppWithNavigation
  • dash_charts.utils_app.AppBase

Class variables⚓︎

app
app_ids

List of all ids for the top-level pages view. Will be mapped to self._il for globally unique ids.

dropdown_links

Base class must create list of tuples [('Link Name', '/link'), ] to use default self.nav_bar().

external_stylesheets
id_collapse
id_pages_content
id_toggler
id_url
init_app_kwargs
logo

Optional path to logo. If None, no logo will be shown in navbar.

modules
name
nav_layouts
nav_lookup
navbar_links

Base class must create list of tuples [('Link Name', '/link'), ] to use default self.nav_bar().

nsi
validation_layout

Methods⚓︎

callback⚓︎

def callback(
    self,
    outputs,
    inputs,
    states,
    pic: bool = False,
    **kwargs: dict
)

Return app callback decorator based on provided components.

Parameters:

Name Description
outputs list of tuples with app_id and property name
inputs list of tuples with app_id and property name
states list of tuples with app_id and property name
pic If True, prevent call on page load (prevent_initial_call). Default is False
**kwargs any additional keyword arguments for self.app.callback

Returns:

Type Description
dict result of self.app.callback()
View Source
    def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
        """Return app callback decorator based on provided components.

        Args:
            outputs: list of tuples with app_id and property name
            inputs: list of tuples with app_id and property name
            states: list of tuples with app_id and property name
            pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
            **kwargs: any additional keyword arguments for `self.app.callback`

        Returns:
            dict: result of `self.app.callback()`

        """
        return self.app.callback(
            *format_app_callback(self._il, outputs, inputs, states),
            prevent_initial_call=pic,
            **kwargs,
        )

create⚓︎

def create(
    self,
    **kwargs
)

Create each navigation componet, storing the layout. Then parent class to create application.

Parameters:

Name Description
kwargs keyword arguments passed to self.create
View Source
    def create(self, **kwargs):
        """Create each navigation componet, storing the layout. Then parent class to create application.

        Args:
            kwargs: keyword arguments passed to `self.create`

        """
        # Initialize the lookup for each tab then configure each tab
        self.nav_lookup = OrderedDict([(tab.name, tab) for tab in self.define_nav_elements()])
        self.nav_layouts = {}
        for nav_name, nav in self.nav_lookup.items():
            nav.create(assign_layout=False)
            self.nav_layouts[nav_name] = nav.return_layout()

        # Store validation_layout that is later used for callback verification in base class
        self.validation_layout = [*map(deepcopy, self.nav_layouts.values())]

        # Initialize parent application that handles navigation
        super().create(**kwargs)

create_callbacks⚓︎

def create_callbacks(
    self
) -> None

Register the navigation callback.

View Source
    def create_callbacks(self) -> None:
        """Register the navigation callback."""
        outputs = [(self.id_pages_content, 'children')]
        inputs = [(self.id_url, 'pathname')]

        @self.callback(outputs, inputs, [])
        def render_page(pathname):
            try:
                # TODO: Demo how pages could use parameters from pathname
                return [self.nav_layouts[self.select_page_name(pathname)]]
            except Exception as err:
                return [html.Div(children=[f'Error rendering "{pathname}":\n{err}'])]

        @self.callback(
            [(self.id_collapse, 'is_open')],
            [(self.id_toggler, 'n_clicks')],
            [(self.id_collapse, 'is_open')],
        )
        def toggle_navbar_collapse(n_clicks, is_open):
            return [not is_open if n_clicks else is_open]

create_elements⚓︎

def create_elements(
    self
) -> None

Override method as not needed at navigation-level.

View Source
    def create_elements(self) -> None:
        """Override method as not needed at navigation-level."""
        ...  # pragma: no cover

define_nav_elements⚓︎

def define_nav_elements(
    self
)

Return list of initialized pages or tabs accordingly.

Should return, list: each item is an initialized app (ex [AppBase(self.app)] in the order each tab is rendered

Raises:

Type Description
NotImplementedError Child class must implement this method
View Source
    def define_nav_elements(self):
        """Return list of initialized pages or tabs accordingly.

        Should return, list: each item is an initialized app (ex `[AppBase(self.app)]` in the order each tab is rendered

        Raises:
            NotImplementedError: Child class must implement this method

        """
        raise NotImplementedError('define_nav_elements must be implemented by child class')  # pragma: no cover

generate_data⚓︎

def generate_data(
    self
) -> None

Recommended method for generating data stored in memory. Called in initialization.

View Source
    def generate_data(self) -> None:
        """Recommended method for generating data stored in memory. Called in initialization."""
        ...

get_server⚓︎

def get_server(
    self
)

Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

Returns:

Type Description
dict the Flask server component of the Dash app
View Source
    def get_server(self):
        """Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

        Returns:
            dict: the Flask `server` component of the Dash app

        """
        return self.app.server

initialization⚓︎

def initialization(
    self
) -> None

Initialize ids with self.register_uniq_ids([...]) and other one-time actions.

View Source
    def initialization(self) -> None:
        """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
        super().initialization()
        self.register_uniq_ids(self.app_ids)
def nav_bar(
    self
)

Return the HTML elements for the navigation menu.

Returns:

Type Description
dict Dash HTML object
View Source
    def nav_bar(self):
        """Return the HTML elements for the navigation menu.

        Returns:
            dict: Dash HTML object

        """
        # Create brand icon and name where icon in optional
        brand = []
        if self.logo:
            brand.append(dbc.Col(html.Img(src=self.logo, height='25px')))
        brand.append(dbc.Col(dbc.NavbarBrand(self.name, className='ml-2')))
        # Create links in navbar and dropdown. Both are optional
        links = []
        if self.navbar_links:
            links.append(
                dbc.Nav(
                    children=[dbc.NavItem(dbc.NavLink(name, href=link)) for name, link in self.navbar_links],
                    fill=True,
                    navbar=True,
                ),
            )
        if self.dropdown_links:
            links.append(
                dbc.Nav(
                    dbc.DropdownMenu(
                        children=[dbc.DropdownMenuItem(name, href=link) for name, link in self.dropdown_links],
                        in_navbar=True,
                        label='Links',
                        nav=True,
                    ),
                    navbar=True,
                ),
            )
        # Layout default navbar
        return dbc.Navbar(
            children=[
                dbc.NavLink(
                    [
                        dbc.Row(
                            children=brand,
                            align='center g-0',
                        ),
                    ], href='/',
                ),
                dbc.NavbarToggler(id=self._il[self.id_toggler]),
                dbc.Collapse(
                    dbc.Row(
                        children=links,
                        className='flex-nowrap mt-3 mt-md-0 g-0',
                        align='center',
                    ),
                    id=self._il[self.id_collapse],
                    navbar=True,
                ),
            ],
            sticky='top',
            color='dark',
            dark=True,
        )

override_module_defaults⚓︎

def override_module_defaults(
    self
) -> None

Override default values from modules.

View Source
    def override_module_defaults(self) -> None:
        """Override default values from modules."""
        ...

register_uniq_ids⚓︎

def register_uniq_ids(
    self,
    app_ids: List[str]
) -> None

Register the app_ids to the corresponding global_id in the self._il lookup dictionary.

The app_ids must be unique within this App so that a layout can be created. This method registers self._il which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child class of this base App to be resused multiple times within a tabbed or multi-page application without id-collision

Parameters:

Name Description
app_ids list of strings that are unique within this App
View Source
    def register_uniq_ids(self, app_ids: List[str]) -> None:
        """Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.

        The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
          which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
          class of this base App to be resused multiple times within a tabbed or multi-page application without
          id-collision

        Args:
            app_ids: list of strings that are unique within this App

        """
        self._il = deepcopy(self._il)
        for app_id in app_ids:
            self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')

return_layout⚓︎

def return_layout(
    self
) -> dict

Return Dash application layout.

Returns:

Type Description
dict Dash HTML object
View Source
    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object

        """
        return html.Div(
            children=[
                dcc.Location(id=self._il[self.id_url], refresh=False),
                self.nav_bar(),
                html.Div(id=self._il[self.id_pages_content]),
            ],
        )

run⚓︎

def run(
    self,
    **dash_kwargs: dict
) -> None

Launch the Dash server instance.

Parameters:

Name Description
**dash_kwargs keyword arguments for Dash.run_server()
View Source
    def run(self, **dash_kwargs: dict) -> None:
        """Launch the Dash server instance.

        Args:
            **dash_kwargs: keyword arguments for `Dash.run_server()`

        """
        self.app.run_server(**dash_kwargs)  # pragma: no cover

select_page_name⚓︎

def select_page_name(
    self,
    pathname
)

Return the page name determined based on the pathname.

Should return str: page name

Parameters:

Name Description
pathname relative pathname from URL

Raises:

Type Description
NotImplementedError Child class must implement this method
View Source
    def select_page_name(self, pathname):
        """Return the page name determined based on the pathname.

        Should return str: page name

        Args:
            pathname: relative pathname from URL

        Raises:
            NotImplementedError: Child class must implement this method

        """
        raise NotImplementedError('nav_bar must be implemented by child class')  # pragma: no cover

verify_app_initialization⚓︎

def verify_app_initialization(
    self
) -> None

Check that the app was properly initialized.

Raises:

Type Description
RuntimeError if child class has not called self.register_uniq_ids
View Source
    def verify_app_initialization(self) -> None:
        """Check that the app was properly initialized.

        Raises:
            RuntimeError: if child class has not called `self.register_uniq_ids`

        """
        if not self._il.keys():  # pragma: no cover
            raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')

AppWithNavigation⚓︎

class AppWithNavigation(
    app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class AppWithNavigation(AppBase):
    """Base class for building Dash Application with tabs or URL routing."""

    app = None
    """Main Dash application to pass to all child tabs."""

    nav_lookup = None
    """OrderedDict based on the list of tuples from `self.define_nav_elements()`."""

    nav_layouts = None
    """Dictionary with nav_names as keys and corresponding layout as value."""

    def define_nav_elements(self):
        """Return list of initialized pages or tabs accordingly.

        Should return, list: each item is an initialized app (ex `[AppBase(self.app)]` in the order each tab is rendered

        Raises:
            NotImplementedError: Child class must implement this method

        """
        raise NotImplementedError('define_nav_elements must be implemented by child class')  # pragma: no cover

    def create(self, **kwargs):
        """Create each navigation componet, storing the layout. Then parent class to create application.

        Args:
            kwargs: keyword arguments passed to `self.create`

        """
        # Initialize the lookup for each tab then configure each tab
        self.nav_lookup = OrderedDict([(tab.name, tab) for tab in self.define_nav_elements()])
        self.nav_layouts = {}
        for nav_name, nav in self.nav_lookup.items():
            nav.create(assign_layout=False)
            self.nav_layouts[nav_name] = nav.return_layout()

        # Store validation_layout that is later used for callback verification in base class
        self.validation_layout = [*map(deepcopy, self.nav_layouts.values())]

        # Initialize parent application that handles navigation
        super().create(**kwargs)

    def initialization(self) -> None:
        """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
        super().initialization()
        self.register_uniq_ids(self.app_ids)

    def create_elements(self) -> None:
        """Override method as not needed at navigation-level."""
        ...  # pragma: no cover

    def create_callbacks(self) -> None:
        """Override method as not needed at navigation-level."""
        ...  # pragma: no cover

Ancestors (in MRO)⚓︎

  • dash_charts.utils_app.AppBase

Descendants⚓︎

  • dash_charts.utils_app_with_navigation.AppWithTabs
  • dash_charts.utils_app_with_navigation.AppMultiPage

Class variables⚓︎

app

Main Dash application to pass to all child tabs.

external_stylesheets
init_app_kwargs
modules
name
nav_layouts

Dictionary with nav_names as keys and corresponding layout as value.

nav_lookup

OrderedDict based on the list of tuples from self.define_nav_elements().

nsi
validation_layout

Methods⚓︎

callback⚓︎

def callback(
    self,
    outputs,
    inputs,
    states,
    pic: bool = False,
    **kwargs: dict
)

Return app callback decorator based on provided components.

Parameters:

Name Description
outputs list of tuples with app_id and property name
inputs list of tuples with app_id and property name
states list of tuples with app_id and property name
pic If True, prevent call on page load (prevent_initial_call). Default is False
**kwargs any additional keyword arguments for self.app.callback

Returns:

Type Description
dict result of self.app.callback()
View Source
    def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
        """Return app callback decorator based on provided components.

        Args:
            outputs: list of tuples with app_id and property name
            inputs: list of tuples with app_id and property name
            states: list of tuples with app_id and property name
            pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
            **kwargs: any additional keyword arguments for `self.app.callback`

        Returns:
            dict: result of `self.app.callback()`

        """
        return self.app.callback(
            *format_app_callback(self._il, outputs, inputs, states),
            prevent_initial_call=pic,
            **kwargs,
        )

create⚓︎

def create(
    self,
    **kwargs
)

Create each navigation componet, storing the layout. Then parent class to create application.

Parameters:

Name Description
kwargs keyword arguments passed to self.create
View Source
    def create(self, **kwargs):
        """Create each navigation componet, storing the layout. Then parent class to create application.

        Args:
            kwargs: keyword arguments passed to `self.create`

        """
        # Initialize the lookup for each tab then configure each tab
        self.nav_lookup = OrderedDict([(tab.name, tab) for tab in self.define_nav_elements()])
        self.nav_layouts = {}
        for nav_name, nav in self.nav_lookup.items():
            nav.create(assign_layout=False)
            self.nav_layouts[nav_name] = nav.return_layout()

        # Store validation_layout that is later used for callback verification in base class
        self.validation_layout = [*map(deepcopy, self.nav_layouts.values())]

        # Initialize parent application that handles navigation
        super().create(**kwargs)

create_callbacks⚓︎

def create_callbacks(
    self
) -> None

Override method as not needed at navigation-level.

View Source
    def create_callbacks(self) -> None:
        """Override method as not needed at navigation-level."""
        ...  # pragma: no cover

create_elements⚓︎

def create_elements(
    self
) -> None

Override method as not needed at navigation-level.

View Source
    def create_elements(self) -> None:
        """Override method as not needed at navigation-level."""
        ...  # pragma: no cover

define_nav_elements⚓︎

def define_nav_elements(
    self
)

Return list of initialized pages or tabs accordingly.

Should return, list: each item is an initialized app (ex [AppBase(self.app)] in the order each tab is rendered

Raises:

Type Description
NotImplementedError Child class must implement this method
View Source
    def define_nav_elements(self):
        """Return list of initialized pages or tabs accordingly.

        Should return, list: each item is an initialized app (ex `[AppBase(self.app)]` in the order each tab is rendered

        Raises:
            NotImplementedError: Child class must implement this method

        """
        raise NotImplementedError('define_nav_elements must be implemented by child class')  # pragma: no cover

generate_data⚓︎

def generate_data(
    self
) -> None

Recommended method for generating data stored in memory. Called in initialization.

View Source
    def generate_data(self) -> None:
        """Recommended method for generating data stored in memory. Called in initialization."""
        ...

get_server⚓︎

def get_server(
    self
)

Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

Returns:

Type Description
dict the Flask server component of the Dash app
View Source
    def get_server(self):
        """Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

        Returns:
            dict: the Flask `server` component of the Dash app

        """
        return self.app.server

initialization⚓︎

def initialization(
    self
) -> None

Initialize ids with self.register_uniq_ids([...]) and other one-time actions.

View Source
    def initialization(self) -> None:
        """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
        super().initialization()
        self.register_uniq_ids(self.app_ids)

override_module_defaults⚓︎

def override_module_defaults(
    self
) -> None

Override default values from modules.

View Source
    def override_module_defaults(self) -> None:
        """Override default values from modules."""
        ...

register_uniq_ids⚓︎

def register_uniq_ids(
    self,
    app_ids: List[str]
) -> None

Register the app_ids to the corresponding global_id in the self._il lookup dictionary.

The app_ids must be unique within this App so that a layout can be created. This method registers self._il which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child class of this base App to be resused multiple times within a tabbed or multi-page application without id-collision

Parameters:

Name Description
app_ids list of strings that are unique within this App
View Source
    def register_uniq_ids(self, app_ids: List[str]) -> None:
        """Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.

        The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
          which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
          class of this base App to be resused multiple times within a tabbed or multi-page application without
          id-collision

        Args:
            app_ids: list of strings that are unique within this App

        """
        self._il = deepcopy(self._il)
        for app_id in app_ids:
            self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')

return_layout⚓︎

def return_layout(
    self
) -> dict

Return Dash application layout.

Returns:

Type Description
dict Dash HTML object. Default is simple HTML text
View Source
    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object. Default is simple HTML text

        """
        return html.Div(['Welcome to the BaseApp! Override return_layout() in child class.'])  # pragma: no cover

run⚓︎

def run(
    self,
    **dash_kwargs: dict
) -> None

Launch the Dash server instance.

Parameters:

Name Description
**dash_kwargs keyword arguments for Dash.run_server()
View Source
    def run(self, **dash_kwargs: dict) -> None:
        """Launch the Dash server instance.

        Args:
            **dash_kwargs: keyword arguments for `Dash.run_server()`

        """
        self.app.run_server(**dash_kwargs)  # pragma: no cover

verify_app_initialization⚓︎

def verify_app_initialization(
    self
) -> None

Check that the app was properly initialized.

Raises:

Type Description
RuntimeError if child class has not called self.register_uniq_ids
View Source
    def verify_app_initialization(self) -> None:
        """Check that the app was properly initialized.

        Raises:
            RuntimeError: if child class has not called `self.register_uniq_ids`

        """
        if not self._il.keys():  # pragma: no cover
            raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')

AppWithTabs⚓︎

class AppWithTabs(
    app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class AppWithTabs(AppWithNavigation):
    """Base class for building Dash Application with tabs."""

    # App ids
    id_tabs_content = 'tabs-wrapper'
    id_tabs_select = 'tabs-content'

    app_ids = [id_tabs_content, id_tabs_select]
    """List of all ids for the top-level tab view. Will be mapped to `self._il` for globally unique ids."""

    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object

        """
        tabs = [dcc.Tab(label=name, value=name) for name, tab in self.nav_lookup.items()]
        return html.Div(
            children=[
                dcc.Tabs(
                    id=self._il[self.id_tabs_select], value=list(self.nav_lookup.keys())[0],
                    children=tabs,
                ),
                html.Div(id=self._il[self.id_tabs_content]),
            ],
        )

    def create_callbacks(self) -> None:
        """Register the navigation callback."""
        outputs = [(self.id_tabs_content, 'children')]
        inputs = [(self.id_tabs_select, 'value')]

        @self.callback(outputs, inputs, [])
        def render_tab(tab_name):
            return [self.nav_layouts[tab_name]]

Ancestors (in MRO)⚓︎

  • dash_charts.utils_app_with_navigation.AppWithNavigation
  • dash_charts.utils_app.AppBase

Descendants⚓︎

  • dash_charts.utils_app_with_navigation.FullScreenAppWithTabs

Class variables⚓︎

app
app_ids

List of all ids for the top-level tab view. Will be mapped to self._il for globally unique ids.

external_stylesheets
id_tabs_content
id_tabs_select
init_app_kwargs
modules
name
nav_layouts
nav_lookup
nsi
validation_layout

Methods⚓︎

callback⚓︎

def callback(
    self,
    outputs,
    inputs,
    states,
    pic: bool = False,
    **kwargs: dict
)

Return app callback decorator based on provided components.

Parameters:

Name Description
outputs list of tuples with app_id and property name
inputs list of tuples with app_id and property name
states list of tuples with app_id and property name
pic If True, prevent call on page load (prevent_initial_call). Default is False
**kwargs any additional keyword arguments for self.app.callback

Returns:

Type Description
dict result of self.app.callback()
View Source
    def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
        """Return app callback decorator based on provided components.

        Args:
            outputs: list of tuples with app_id and property name
            inputs: list of tuples with app_id and property name
            states: list of tuples with app_id and property name
            pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
            **kwargs: any additional keyword arguments for `self.app.callback`

        Returns:
            dict: result of `self.app.callback()`

        """
        return self.app.callback(
            *format_app_callback(self._il, outputs, inputs, states),
            prevent_initial_call=pic,
            **kwargs,
        )

create⚓︎

def create(
    self,
    **kwargs
)

Create each navigation componet, storing the layout. Then parent class to create application.

Parameters:

Name Description
kwargs keyword arguments passed to self.create
View Source
    def create(self, **kwargs):
        """Create each navigation componet, storing the layout. Then parent class to create application.

        Args:
            kwargs: keyword arguments passed to `self.create`

        """
        # Initialize the lookup for each tab then configure each tab
        self.nav_lookup = OrderedDict([(tab.name, tab) for tab in self.define_nav_elements()])
        self.nav_layouts = {}
        for nav_name, nav in self.nav_lookup.items():
            nav.create(assign_layout=False)
            self.nav_layouts[nav_name] = nav.return_layout()

        # Store validation_layout that is later used for callback verification in base class
        self.validation_layout = [*map(deepcopy, self.nav_layouts.values())]

        # Initialize parent application that handles navigation
        super().create(**kwargs)

create_callbacks⚓︎

def create_callbacks(
    self
) -> None

Register the navigation callback.

View Source
    def create_callbacks(self) -> None:
        """Register the navigation callback."""
        outputs = [(self.id_tabs_content, 'children')]
        inputs = [(self.id_tabs_select, 'value')]

        @self.callback(outputs, inputs, [])
        def render_tab(tab_name):
            return [self.nav_layouts[tab_name]]

create_elements⚓︎

def create_elements(
    self
) -> None

Override method as not needed at navigation-level.

View Source
    def create_elements(self) -> None:
        """Override method as not needed at navigation-level."""
        ...  # pragma: no cover

define_nav_elements⚓︎

def define_nav_elements(
    self
)

Return list of initialized pages or tabs accordingly.

Should return, list: each item is an initialized app (ex [AppBase(self.app)] in the order each tab is rendered

Raises:

Type Description
NotImplementedError Child class must implement this method
View Source
    def define_nav_elements(self):
        """Return list of initialized pages or tabs accordingly.

        Should return, list: each item is an initialized app (ex `[AppBase(self.app)]` in the order each tab is rendered

        Raises:
            NotImplementedError: Child class must implement this method

        """
        raise NotImplementedError('define_nav_elements must be implemented by child class')  # pragma: no cover

generate_data⚓︎

def generate_data(
    self
) -> None

Recommended method for generating data stored in memory. Called in initialization.

View Source
    def generate_data(self) -> None:
        """Recommended method for generating data stored in memory. Called in initialization."""
        ...

get_server⚓︎

def get_server(
    self
)

Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

Returns:

Type Description
dict the Flask server component of the Dash app
View Source
    def get_server(self):
        """Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

        Returns:
            dict: the Flask `server` component of the Dash app

        """
        return self.app.server

initialization⚓︎

def initialization(
    self
) -> None

Initialize ids with self.register_uniq_ids([...]) and other one-time actions.

View Source
    def initialization(self) -> None:
        """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
        super().initialization()
        self.register_uniq_ids(self.app_ids)

override_module_defaults⚓︎

def override_module_defaults(
    self
) -> None

Override default values from modules.

View Source
    def override_module_defaults(self) -> None:
        """Override default values from modules."""
        ...

register_uniq_ids⚓︎

def register_uniq_ids(
    self,
    app_ids: List[str]
) -> None

Register the app_ids to the corresponding global_id in the self._il lookup dictionary.

The app_ids must be unique within this App so that a layout can be created. This method registers self._il which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child class of this base App to be resused multiple times within a tabbed or multi-page application without id-collision

Parameters:

Name Description
app_ids list of strings that are unique within this App
View Source
    def register_uniq_ids(self, app_ids: List[str]) -> None:
        """Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.

        The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
          which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
          class of this base App to be resused multiple times within a tabbed or multi-page application without
          id-collision

        Args:
            app_ids: list of strings that are unique within this App

        """
        self._il = deepcopy(self._il)
        for app_id in app_ids:
            self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')

return_layout⚓︎

def return_layout(
    self
) -> dict

Return Dash application layout.

Returns:

Type Description
dict Dash HTML object
View Source
    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object

        """
        tabs = [dcc.Tab(label=name, value=name) for name, tab in self.nav_lookup.items()]
        return html.Div(
            children=[
                dcc.Tabs(
                    id=self._il[self.id_tabs_select], value=list(self.nav_lookup.keys())[0],
                    children=tabs,
                ),
                html.Div(id=self._il[self.id_tabs_content]),
            ],
        )

run⚓︎

def run(
    self,
    **dash_kwargs: dict
) -> None

Launch the Dash server instance.

Parameters:

Name Description
**dash_kwargs keyword arguments for Dash.run_server()
View Source
    def run(self, **dash_kwargs: dict) -> None:
        """Launch the Dash server instance.

        Args:
            **dash_kwargs: keyword arguments for `Dash.run_server()`

        """
        self.app.run_server(**dash_kwargs)  # pragma: no cover

verify_app_initialization⚓︎

def verify_app_initialization(
    self
) -> None

Check that the app was properly initialized.

Raises:

Type Description
RuntimeError if child class has not called self.register_uniq_ids
View Source
    def verify_app_initialization(self) -> None:
        """Check that the app was properly initialized.

        Raises:
            RuntimeError: if child class has not called `self.register_uniq_ids`

        """
        if not self._il.keys():  # pragma: no cover
            raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')

FullScreenAppWithTabs⚓︎

class FullScreenAppWithTabs(
    app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class FullScreenAppWithTabs(AppWithTabs):  # noqa: H601
    """Base class for building Dash Application with tabs that uses the full window."""

    tabs_location = 'left'
    """Tab orientation setting. One of `(left, top, bottom, right)`."""

    tabs_margin = '10%'
    """Adjust this setting based on the width or height of the tabs to prevent the content from overlapping the tabs."""

    tabs_compact = False
    """Boolean setting to toggle between a padded tab layout if False and a minimal compact version if True."""

    def verify_app_initialization(self):
        """Check that the app was properly initialized.

        Raises:
            RuntimeError: if child class has not called `self.register_uniq_ids`

        """
        super().verify_app_initialization()
        allowed_locations = ('left', 'top', 'bottom', 'right')
        if self.tabs_location not in allowed_locations:  # pragma: no cover
            raise RuntimeError(f'`self.tabs_location = {self.tabs_location}` is not in {allowed_locations}')

    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object

        """
        return html.Div(
            children=[
                self.tab_menu(),
                html.Div(
                    style={f'margin-{self.tabs_location}': self.tabs_margin},
                    children=[html.Div(id=self._il[self.id_tabs_content])],
                ),
            ],
        )

    def generate_tab_kwargs(self):
        """Create the tab keyword arguments. Intended to be modified through inheritance.

        Returns:
            tuple: keyword arguments and styling for the dcc.Tab elements

                - tab_kwargs: with at minimum keys `(style, selected_style)` for dcc.Tab
                - tabs_kwargs: to be passed to dcc.Tabs
                - tabs_style: style for the dcc.Tabs HTML element

        """
        # Unselected tab style
        if self.tabs_compact:
            tab_style = {'padding': '2px 4px 2px 4px'}
            tabs_padding = '6px 0 0 2px'
        else:
            tab_style = {'padding': '10px 20px 10px 20px'}
            tabs_padding = '15px 0 0 5px'
        # Extend tab style for selected case
        selected_style = deepcopy(tab_style)
        opposite_lookup = {'top': 'bottom', 'bottom': 'top', 'left': 'right', 'right': 'left'}
        tabs_style = {   # noqa: ECE001
            'backgroundColor': '#F9F9F9',
            'padding': tabs_padding,
            'position': 'fixed',
            'zIndex': '999',
            f'border{opposite_lookup[self.tabs_location].title()}': '1px solid #d6d6d6',
            self.tabs_location: '0',
        }
        if self.tabs_location in ['left', 'right']:
            # Configure for vertical case
            selected_style['border-left'] = '3px solid #119DFF'
            tabs_kwargs = {
                'vertical': True,
                'style': {'width': '100%'},
                'parent_style': {'width': '100%'},
            }
            tabs_style['top'] = '0'
            tabs_style['bottom'] = '0'
            tabs_style['width'] = 'auto'
        else:
            # Configure for horizontal case
            selected_style['border-top'] = '3px solid #119DFF'
            tabs_kwargs = {}
            tabs_style['height'] = 'auto'
            tabs_style['right'] = '0'
            tabs_style['left'] = '0'

        tab_kwargs = {'style': tab_style, 'selected_style': selected_style}
        return (tab_kwargs, tabs_kwargs, tabs_style)

    def tab_menu(self):
        """Return the HTML elements for the tab menu.

        Returns:
            dict: Dash HTML object

        """
        tab_kwargs, tabs_kwargs, tabs_style = self.generate_tab_kwargs()
        tabs = [dcc.Tab(label=name, value=name, **tab_kwargs) for name, tab in self.nav_lookup.items()]
        return html.Div(
            children=[
                dcc.Tabs(
                    id=self._il[self.id_tabs_select], value=list(self.nav_lookup.keys())[0],
                    children=tabs, **tabs_kwargs,
                ),
            ], style=tabs_style,
        )

Ancestors (in MRO)⚓︎

  • dash_charts.utils_app_with_navigation.AppWithTabs
  • dash_charts.utils_app_with_navigation.AppWithNavigation
  • dash_charts.utils_app.AppBase

Descendants⚓︎

  • dash_charts.app_px.InteractivePXApp

Class variables⚓︎

app
app_ids
external_stylesheets
id_tabs_content
id_tabs_select
init_app_kwargs
modules
name
nav_layouts
nav_lookup
nsi
tabs_compact

Boolean setting to toggle between a padded tab layout if False and a minimal compact version if True.

tabs_location

Tab orientation setting. One of (left, top, bottom, right).

tabs_margin

Adjust this setting based on the width or height of the tabs to prevent the content from overlapping the tabs.

validation_layout

Methods⚓︎

callback⚓︎

def callback(
    self,
    outputs,
    inputs,
    states,
    pic: bool = False,
    **kwargs: dict
)

Return app callback decorator based on provided components.

Parameters:

Name Description
outputs list of tuples with app_id and property name
inputs list of tuples with app_id and property name
states list of tuples with app_id and property name
pic If True, prevent call on page load (prevent_initial_call). Default is False
**kwargs any additional keyword arguments for self.app.callback

Returns:

Type Description
dict result of self.app.callback()
View Source
    def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
        """Return app callback decorator based on provided components.

        Args:
            outputs: list of tuples with app_id and property name
            inputs: list of tuples with app_id and property name
            states: list of tuples with app_id and property name
            pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
            **kwargs: any additional keyword arguments for `self.app.callback`

        Returns:
            dict: result of `self.app.callback()`

        """
        return self.app.callback(
            *format_app_callback(self._il, outputs, inputs, states),
            prevent_initial_call=pic,
            **kwargs,
        )

create⚓︎

def create(
    self,
    **kwargs
)

Create each navigation componet, storing the layout. Then parent class to create application.

Parameters:

Name Description
kwargs keyword arguments passed to self.create
View Source
    def create(self, **kwargs):
        """Create each navigation componet, storing the layout. Then parent class to create application.

        Args:
            kwargs: keyword arguments passed to `self.create`

        """
        # Initialize the lookup for each tab then configure each tab
        self.nav_lookup = OrderedDict([(tab.name, tab) for tab in self.define_nav_elements()])
        self.nav_layouts = {}
        for nav_name, nav in self.nav_lookup.items():
            nav.create(assign_layout=False)
            self.nav_layouts[nav_name] = nav.return_layout()

        # Store validation_layout that is later used for callback verification in base class
        self.validation_layout = [*map(deepcopy, self.nav_layouts.values())]

        # Initialize parent application that handles navigation
        super().create(**kwargs)

create_callbacks⚓︎

def create_callbacks(
    self
) -> None

Register the navigation callback.

View Source
    def create_callbacks(self) -> None:
        """Register the navigation callback."""
        outputs = [(self.id_tabs_content, 'children')]
        inputs = [(self.id_tabs_select, 'value')]

        @self.callback(outputs, inputs, [])
        def render_tab(tab_name):
            return [self.nav_layouts[tab_name]]

create_elements⚓︎

def create_elements(
    self
) -> None

Override method as not needed at navigation-level.

View Source
    def create_elements(self) -> None:
        """Override method as not needed at navigation-level."""
        ...  # pragma: no cover

define_nav_elements⚓︎

def define_nav_elements(
    self
)

Return list of initialized pages or tabs accordingly.

Should return, list: each item is an initialized app (ex [AppBase(self.app)] in the order each tab is rendered

Raises:

Type Description
NotImplementedError Child class must implement this method
View Source
    def define_nav_elements(self):
        """Return list of initialized pages or tabs accordingly.

        Should return, list: each item is an initialized app (ex `[AppBase(self.app)]` in the order each tab is rendered

        Raises:
            NotImplementedError: Child class must implement this method

        """
        raise NotImplementedError('define_nav_elements must be implemented by child class')  # pragma: no cover

generate_data⚓︎

def generate_data(
    self
) -> None

Recommended method for generating data stored in memory. Called in initialization.

View Source
    def generate_data(self) -> None:
        """Recommended method for generating data stored in memory. Called in initialization."""
        ...

generate_tab_kwargs⚓︎

def generate_tab_kwargs(
    self
)

Create the tab keyword arguments. Intended to be modified through inheritance.

Returns:

Type Description
tuple keyword arguments and styling for the dcc.Tab elements
- tab_kwargs: with at minimum keys (style, selected_style) for dcc.Tab
- tabs_kwargs: to be passed to dcc.Tabs
- tabs_style: style for the dcc.Tabs HTML element
View Source
    def generate_tab_kwargs(self):
        """Create the tab keyword arguments. Intended to be modified through inheritance.

        Returns:
            tuple: keyword arguments and styling for the dcc.Tab elements

                - tab_kwargs: with at minimum keys `(style, selected_style)` for dcc.Tab
                - tabs_kwargs: to be passed to dcc.Tabs
                - tabs_style: style for the dcc.Tabs HTML element

        """
        # Unselected tab style
        if self.tabs_compact:
            tab_style = {'padding': '2px 4px 2px 4px'}
            tabs_padding = '6px 0 0 2px'
        else:
            tab_style = {'padding': '10px 20px 10px 20px'}
            tabs_padding = '15px 0 0 5px'
        # Extend tab style for selected case
        selected_style = deepcopy(tab_style)
        opposite_lookup = {'top': 'bottom', 'bottom': 'top', 'left': 'right', 'right': 'left'}
        tabs_style = {   # noqa: ECE001
            'backgroundColor': '#F9F9F9',
            'padding': tabs_padding,
            'position': 'fixed',
            'zIndex': '999',
            f'border{opposite_lookup[self.tabs_location].title()}': '1px solid #d6d6d6',
            self.tabs_location: '0',
        }
        if self.tabs_location in ['left', 'right']:
            # Configure for vertical case
            selected_style['border-left'] = '3px solid #119DFF'
            tabs_kwargs = {
                'vertical': True,
                'style': {'width': '100%'},
                'parent_style': {'width': '100%'},
            }
            tabs_style['top'] = '0'
            tabs_style['bottom'] = '0'
            tabs_style['width'] = 'auto'
        else:
            # Configure for horizontal case
            selected_style['border-top'] = '3px solid #119DFF'
            tabs_kwargs = {}
            tabs_style['height'] = 'auto'
            tabs_style['right'] = '0'
            tabs_style['left'] = '0'

        tab_kwargs = {'style': tab_style, 'selected_style': selected_style}
        return (tab_kwargs, tabs_kwargs, tabs_style)

get_server⚓︎

def get_server(
    self
)

Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

Returns:

Type Description
dict the Flask server component of the Dash app
View Source
    def get_server(self):
        """Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

        Returns:
            dict: the Flask `server` component of the Dash app

        """
        return self.app.server

initialization⚓︎

def initialization(
    self
) -> None

Initialize ids with self.register_uniq_ids([...]) and other one-time actions.

View Source
    def initialization(self) -> None:
        """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
        super().initialization()
        self.register_uniq_ids(self.app_ids)

override_module_defaults⚓︎

def override_module_defaults(
    self
) -> None

Override default values from modules.

View Source
    def override_module_defaults(self) -> None:
        """Override default values from modules."""
        ...

register_uniq_ids⚓︎

def register_uniq_ids(
    self,
    app_ids: List[str]
) -> None

Register the app_ids to the corresponding global_id in the self._il lookup dictionary.

The app_ids must be unique within this App so that a layout can be created. This method registers self._il which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child class of this base App to be resused multiple times within a tabbed or multi-page application without id-collision

Parameters:

Name Description
app_ids list of strings that are unique within this App
View Source
    def register_uniq_ids(self, app_ids: List[str]) -> None:
        """Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.

        The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
          which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
          class of this base App to be resused multiple times within a tabbed or multi-page application without
          id-collision

        Args:
            app_ids: list of strings that are unique within this App

        """
        self._il = deepcopy(self._il)
        for app_id in app_ids:
            self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')

return_layout⚓︎

def return_layout(
    self
) -> dict

Return Dash application layout.

Returns:

Type Description
dict Dash HTML object
View Source
    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object

        """
        return html.Div(
            children=[
                self.tab_menu(),
                html.Div(
                    style={f'margin-{self.tabs_location}': self.tabs_margin},
                    children=[html.Div(id=self._il[self.id_tabs_content])],
                ),
            ],
        )

run⚓︎

def run(
    self,
    **dash_kwargs: dict
) -> None

Launch the Dash server instance.

Parameters:

Name Description
**dash_kwargs keyword arguments for Dash.run_server()
View Source
    def run(self, **dash_kwargs: dict) -> None:
        """Launch the Dash server instance.

        Args:
            **dash_kwargs: keyword arguments for `Dash.run_server()`

        """
        self.app.run_server(**dash_kwargs)  # pragma: no cover

tab_menu⚓︎

def tab_menu(
    self
)

Return the HTML elements for the tab menu.

Returns:

Type Description
dict Dash HTML object
View Source
    def tab_menu(self):
        """Return the HTML elements for the tab menu.

        Returns:
            dict: Dash HTML object

        """
        tab_kwargs, tabs_kwargs, tabs_style = self.generate_tab_kwargs()
        tabs = [dcc.Tab(label=name, value=name, **tab_kwargs) for name, tab in self.nav_lookup.items()]
        return html.Div(
            children=[
                dcc.Tabs(
                    id=self._il[self.id_tabs_select], value=list(self.nav_lookup.keys())[0],
                    children=tabs, **tabs_kwargs,
                ),
            ], style=tabs_style,
        )

verify_app_initialization⚓︎

def verify_app_initialization(
    self
)

Check that the app was properly initialized.

Raises:

Type Description
RuntimeError if child class has not called self.register_uniq_ids
View Source
    def verify_app_initialization(self):
        """Check that the app was properly initialized.

        Raises:
            RuntimeError: if child class has not called `self.register_uniq_ids`

        """
        super().verify_app_initialization()
        allowed_locations = ('left', 'top', 'bottom', 'right')
        if self.tabs_location not in allowed_locations:  # pragma: no cover
            raise RuntimeError(f'`self.tabs_location = {self.tabs_location}` is not in {allowed_locations}')

StaticTab⚓︎

class StaticTab(
    app: Union[dash.dash.Dash, NoneType] = None
)
View Source
class StaticTab(AppBase):
    """Simple App without charts or callbacks."""

    basic_style = {
        'marginLeft': 'auto',
        'marginRight': 'auto',
        'maxWidth': '1000px',
        'paddingTop': '10px',
    }

    def initialization(self) -> None:
        """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
        super().initialization()
        self.register_uniq_ids(['N/A'])

    def create_elements(self) -> None:
        """Initialize the charts, tables, and other Dash elements.."""
        ...

    def create_callbacks(self) -> None:
        """Register callbacks necessary for this tab."""
        ...

Ancestors (in MRO)⚓︎

  • dash_charts.utils_app.AppBase

Class variables⚓︎

basic_style
external_stylesheets
init_app_kwargs
modules
name
nsi
validation_layout

Methods⚓︎

callback⚓︎

def callback(
    self,
    outputs,
    inputs,
    states,
    pic: bool = False,
    **kwargs: dict
)

Return app callback decorator based on provided components.

Parameters:

Name Description
outputs list of tuples with app_id and property name
inputs list of tuples with app_id and property name
states list of tuples with app_id and property name
pic If True, prevent call on page load (prevent_initial_call). Default is False
**kwargs any additional keyword arguments for self.app.callback

Returns:

Type Description
dict result of self.app.callback()
View Source
    def callback(self, outputs, inputs, states, pic: bool = False, **kwargs: dict):
        """Return app callback decorator based on provided components.

        Args:
            outputs: list of tuples with app_id and property name
            inputs: list of tuples with app_id and property name
            states: list of tuples with app_id and property name
            pic: If True, prevent call on page load (`prevent_initial_call`). Default is False
            **kwargs: any additional keyword arguments for `self.app.callback`

        Returns:
            dict: result of `self.app.callback()`

        """
        return self.app.callback(
            *format_app_callback(self._il, outputs, inputs, states),
            prevent_initial_call=pic,
            **kwargs,
        )

create⚓︎

def create(
    self,
    assign_layout: bool = True
) -> None

Create the ids, app charts, layout, callbacks, and optional modules.

Parameters:

Name Description
assign_layout if True, will assign self.app.layout. If False, must call self.return_layout separately.
Default is True

Raises:

Type Description
NotImplementedError if child class has not set the self.name data member
View Source
    def create(self, assign_layout: bool = True) -> None:  # noqa: CCR001
        """Create the ids, app charts, layout, callbacks, and optional modules.

        Args:
            assign_layout: if True, will assign `self.app.layout`. If False, must call `self.return_layout` separately.
                Default is True

        Raises:
            NotImplementedError: if child class has not set the `self.name` data member

        """
        if self.name is None:  # pragma: no cover
            raise NotImplementedError('Child class must set `self.name` to a unique string for this app')

        # Initialize app and each module
        self.initialization()
        for mod in self.modules:
            self.register_uniq_ids(mod.all_ids)
        self.override_module_defaults()  # Call optional override method

        # Create charts for app and each module
        self.create_elements()
        for mod in self.modules:
            mod.create_elements(self._il)

        # Create app layout. User must call the return_layout method from each module within own return_layout method
        if assign_layout:
            self.app.layout = self.return_layout()
        if assign_layout and self.validation_layout:
            self.app.validation_layout = [deepcopy(self.app.layout)] + self.validation_layout
            pprint('\n\nValidationLayout?')
            pprint(self.app.validation_layout)

        # Create callbacks for app and each module
        self.create_callbacks()
        for mod in self.modules:
            mod.create_callbacks(self)

        self.verify_app_initialization()

create_callbacks⚓︎

def create_callbacks(
    self
) -> None

Register callbacks necessary for this tab.

View Source
    def create_callbacks(self) -> None:
        """Register callbacks necessary for this tab."""
        ...

create_elements⚓︎

def create_elements(
    self
) -> None

Initialize the charts, tables, and other Dash elements..

View Source
    def create_elements(self) -> None:
        """Initialize the charts, tables, and other Dash elements.."""
        ...

generate_data⚓︎

def generate_data(
    self
) -> None

Recommended method for generating data stored in memory. Called in initialization.

View Source
    def generate_data(self) -> None:
        """Recommended method for generating data stored in memory. Called in initialization."""
        ...

get_server⚓︎

def get_server(
    self
)

Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

Returns:

Type Description
dict the Flask server component of the Dash app
View Source
    def get_server(self):
        """Retrieve server from app instance for production hosting with green unicorn, waitress, IIS, etc.

        Returns:
            dict: the Flask `server` component of the Dash app

        """
        return self.app.server

initialization⚓︎

def initialization(
    self
) -> None

Initialize ids with self.register_uniq_ids([...]) and other one-time actions.

View Source
    def initialization(self) -> None:
        """Initialize ids with `self.register_uniq_ids([...])` and other one-time actions."""
        super().initialization()
        self.register_uniq_ids(['N/A'])

override_module_defaults⚓︎

def override_module_defaults(
    self
) -> None

Override default values from modules.

View Source
    def override_module_defaults(self) -> None:
        """Override default values from modules."""
        ...

register_uniq_ids⚓︎

def register_uniq_ids(
    self,
    app_ids: List[str]
) -> None

Register the app_ids to the corresponding global_id in the self._il lookup dictionary.

The app_ids must be unique within this App so that a layout can be created. This method registers self._il which are a list of globally unique ids (incorporating this App’s unique self.name) allowing for the child class of this base App to be resused multiple times within a tabbed or multi-page application without id-collision

Parameters:

Name Description
app_ids list of strings that are unique within this App
View Source
    def register_uniq_ids(self, app_ids: List[str]) -> None:
        """Register the `app_ids` to the corresponding global_id in the `self._il` lookup dictionary.

        The app_ids must be unique within this App so that a layout can be created. This method registers `self._il`
          which are a list of globally unique ids (incorporating this App's unique `self.name`) allowing for the child
          class of this base App to be resused multiple times within a tabbed or multi-page application without
          id-collision

        Args:
            app_ids: list of strings that are unique within this App

        """
        self._il = deepcopy(self._il)
        for app_id in app_ids:
            self._il[app_id] = f'{self.name}-{app_id}'.replace(' ', '-')

return_layout⚓︎

def return_layout(
    self
) -> dict

Return Dash application layout.

Returns:

Type Description
dict Dash HTML object. Default is simple HTML text
View Source
    def return_layout(self) -> dict:
        """Return Dash application layout.

        Returns:
            dict: Dash HTML object. Default is simple HTML text

        """
        return html.Div(['Welcome to the BaseApp! Override return_layout() in child class.'])  # pragma: no cover

run⚓︎

def run(
    self,
    **dash_kwargs: dict
) -> None

Launch the Dash server instance.

Parameters:

Name Description
**dash_kwargs keyword arguments for Dash.run_server()
View Source
    def run(self, **dash_kwargs: dict) -> None:
        """Launch the Dash server instance.

        Args:
            **dash_kwargs: keyword arguments for `Dash.run_server()`

        """
        self.app.run_server(**dash_kwargs)  # pragma: no cover

verify_app_initialization⚓︎

def verify_app_initialization(
    self
) -> None

Check that the app was properly initialized.

Raises:

Type Description
RuntimeError if child class has not called self.register_uniq_ids
View Source
    def verify_app_initialization(self) -> None:
        """Check that the app was properly initialized.

        Raises:
            RuntimeError: if child class has not called `self.register_uniq_ids`

        """
        if not self._il.keys():  # pragma: no cover
            raise RuntimeError('Child class must first call `self.register_uniq_ids(__)` before self.run()')

Last update: August 5, 2022
Created: August 5, 2022